package de.ret_world.openrpgstudio.mapeditor.scripts;

import de.ret_world.openrpgstudio.editor.script.ScriptObject;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;

/**
 * A TileMap for showing a map in your game. It is organized in Layers.
 *
 * @author Emu
 */
public class TileMap implements ScriptObject {

    public static final String TYPE = "TileMap";
    private String ID = "";
    private int height = 25, width = 25;
    private int tileHeight = 32, tileWidth = 32;
    private ArrayList<Layer> layers = new ArrayList<>();

    @Override
    public void create(LuaValue val) {
        if (!val.get("id").isnil()) {
            ID = val.get("id").toString();
        }
        if (!val.get("height").isnil()) {
            height = val.get("height").toint();
        }
        if (!val.get("width").isnil()) {
            width = val.get("width").toint();
        }
        if (!val.get("tileheight").isnil()) {
            tileHeight = val.get("tileheight").toint();
        }
        if (!val.get("tilewidth").isnil()) {
            tileWidth = val.get("tilewidth").toint();
        }
        if (!val.get("layer").isnil()) {
            if (val.get("layer").istable()) {
                HashMap<Integer, LuaValue> map = new HashMap<>();

                LuaValue k = LuaValue.NIL;
                while (true) {
                    Varargs n = val.get("layer").next(k);
                    if ((k = n.arg1()).isnil()) {
                        break;
                    }
                    LuaValue v = n.arg(2);
                    if (v.istable()) {
                        map.put(k.toint(), v);
                    }
                }

                ArrayList<Integer> keys = new ArrayList<>(map.keySet());
                Collections.sort(keys);

                layers.clear();
                for (int i = 0; i < keys.size(); i++) {
                    Layer l = new Layer();
                    l.setParentMap(this);
                    l.setIndex(i);
                    l.create(map.get(keys.get(i)));
                    layers.add(l);
                }
            }
        }
    }

    @Override
    public LuaTable toLua() {
        LuaTable lua = new LuaTable();
        lua.set("id", LuaTable.valueOf(ID));
        lua.set("height", LuaTable.valueOf(height));
        lua.set("width", LuaTable.valueOf(width));
        lua.set("tileheight", LuaTable.valueOf(tileHeight));
        lua.set("tilewidth", LuaTable.valueOf(tileWidth));
        LuaTable layersT = new LuaTable();
        for (Layer l : layers) {
            layersT.add(l.toLua());
        }
        lua.set("layer", layersT);

        return lua;
    }

    @Override
    public String toScript() {
        String s = "tilemap = {} -- init new tilemap\n"
                + "tilemap.id = '" + ID + "'\n"
                + "tilemap.width = " + width + "\n"
                + "tilemap.height = " + height + "\n"
                + "tilemap.tilewidth = " + tileWidth + "\n"
                + "tilemap.tileheight = " + tileHeight + "\n"
                + "tilemap.layer = {} -- init map layers\n";
        for (Layer l : layers) {
            s += l.toScript();
        }

        return s;
    }

    public String getID() {
        return ID;
    }

    public void setID(String ID) {
        this.ID = ID;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public void addLayer(Layer layer) {
        layers.add(layer);
        layer.setParentMap(this);
        layer.setIndex(layers.size() - 1);
    }

    public void layerUp(Layer layer) {
        int index = layer.getIndex();
        if (index > 0) {
            Layer tmp = layers.get(index - 1);
            layers.set(index - 1, layer);
            layer.setIndex(index - 1);
            layers.set(index, tmp);
            tmp.setIndex(index);
        }
    }

    public void layerDown(Layer layer) {
        int index = layer.getIndex();
        if (index < layers.size() - 1) {
            Layer tmp = layers.get(index + 1);
            layers.set(index + 1, layer);
            layer.setIndex(index + 1);
            layers.set(index, tmp);
            tmp.setIndex(index);
        }
    }

    public ArrayList<Layer> getLayers() {
        return layers;
    }

    public int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public int getTileHeight() {
        return tileHeight;
    }

    public void setTileHeight(int tileHeight) {
        this.tileHeight = tileHeight;
    }

    public int getTileWidth() {
        return tileWidth;
    }

    public void setTileWidth(int tileWidth) {
        this.tileWidth = tileWidth;
    }

    @Override
    public String toString() {
        return getID();
    }
}
